/**
 ***********************************************************************************************************************
 * Copyright (c) 2021, XIE LI Co.,Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * @file        tcp_server_select.c
 *
 * @brief       tcp_server_select functions.
 *
 * @revision
 * Date         Author          Notes
 * 2021-09-30   Xie Li      First Version
 ***********************************************************************************************************************
 */
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <unistd.h>
#include <pthread.h>

#define HOST_PORT_NUM   60000
#define HOST_BACKLOG    3

/**
 ***********************************************************************************************************************
 * @brief           tcp_server_select_run
 *
 * @param[in]       none
 *
 * @return          none
 ***********************************************************************************************************************
 */
int tcp_server_select_run(void)
{
    struct sockaddr_in srv_addr;
    int listen_fd, sock_fd_max;
    char add_str[INET_ADDRSTRLEN];
    fd_set all_set, read_set;
    char buf[64];
    char *message = "hello client";    

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd == -1) {
        printf("Socket create failed\r\n");
        return -1;
    }

    memset(&srv_addr, 0, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    srv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    srv_addr.sin_port = htons(HOST_PORT_NUM);

    if (bind(listen_fd, (struct sockaddr *)&srv_addr, sizeof(struct sockaddr_in)) == -1) {
        printf("Socket bind failed, errno=%d\r\n", errno);
        goto exit;
    }

    if (listen(listen_fd, HOST_BACKLOG) == -1) {
        printf("Socket listen failed, errno=%d\r\n", errno);
        goto exit;        
    }

    FD_ZERO(&all_set);
    FD_SET(listen_fd, &all_set);
    sock_fd_max = listen_fd;

    while (1) {
        /* 监听句柄的可读性 */
        read_set = all_set;
        if (select(sock_fd_max+1, &read_set, NULL, NULL, NULL) == -1) {
            printf("Socket select failed, errno=%d\r\n", errno);
            goto exit;                
        }
        for (int sock_fd = 0; sock_fd <= sock_fd_max; sock_fd++) {
            if (!FD_ISSET(sock_fd, &read_set)) {
                continue;
            }
            /* 新的客户端连接 */
            if (sock_fd == listen_fd) {
                struct sockaddr_in cli_addr;
                socklen_t addr_len = sizeof(struct sockaddr_in);
                int cli_fd = accept(listen_fd, (struct sockaddr *)&cli_addr, &addr_len);
                if (cli_fd == -1) {
                    printf("Socket accept failed, errno=%d\r\n", errno);
                    goto exit;
                }
                inet_ntop(AF_INET, &cli_addr.sin_addr, add_str, INET_ADDRSTRLEN);
                printf("Accecpt a connection from client (%s:%d)\r\n", add_str, ntohs(cli_addr.sin_port));
                /* 添加到监听句柄集 */
                FD_SET(cli_fd, &all_set);
                if (cli_fd > sock_fd_max) {
                    sock_fd_max = cli_fd;
                }
            } else { /* 客户端通信数据 */
                /* Recv data */
                int len = recv(sock_fd, buf, sizeof(buf), 0);
                if (len <= 0 ) {
                    if (len == -1) {
                        printf("Receive from client failed, errno=%d\r\n", errno);
                    } else {
                        printf("The peer client has been closed\r\n");
                    }
                    /* 从监听句柄中删除 */
                    FD_CLR(sock_fd, &all_set); 
                    shutdown(sock_fd, SHUT_RDWR);
                    // close(sock_fd);
                    continue;  
                }
                printf("Received %d bytes from client:%.*s\r\n", len, len, buf);

                /* Send data */
                len = send(sock_fd, message, strlen(message), 0);
                if (len <= 0 ) {
                    if (len == -1) {
                        printf("Receive from client failed, errno=%d\r\n", errno);
                    } else {
                        printf("The peer client has been closed\r\n");
                    }
                    /* 从监听句柄中删除 */
                    FD_CLR(sock_fd, &all_set); 
                    shutdown(sock_fd, SHUT_RDWR);
                    // close(sock_fd);  
                }             
            }
        }
        
    }

    return 0;    

exit:
    shutdown(listen_fd, SHUT_RDWR);
    // close(listen_fd);
    return -1;
}